#include "decodevideo.h"

DecodeVideo::DecodeVideo()
    :QThread()
{
    this->speed = 40;
//    this->encoder = new EncodeVideo();
//    this->encoder->initEncode();
    this->isRecord = false;
}

void DecodeVideo::openVideo()
{
    //1.注册组件
    av_register_all();
    //2.打开视频
    AVFormatContext * formatcontext;
    formatcontext = avformat_alloc_context();
    int res = avformat_open_input(&formatcontext, QString("%1").arg(this->path).toStdString().c_str(), nullptr, nullptr);
    if(res!=0){
        qDebug() << "open video fail";
    }
    else {
        qDebug() << "open video success";
    }
    //3.查找流媒体数据 判断码流数据
    res = avformat_find_stream_info(formatcontext, nullptr);
    if(res<0){
        qDebug()<< "find_stream fail";
    }
    else {
        qDebug() << "find_stream success";
    }
    //4.判断码流数据是否为视频码流
    int video_index = -1;
    for(int i=0;i<formatcontext->nb_streams;i++){
        //nb_streams 有多少种码流数据的信息
        if(formatcontext->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO)
        {
            video_index = i;
            break;
        }
    }
    //如果下标还是-1，就没有找到
    if(video_index==-1){
        qDebug() << "video stream no find";
    }
    else {
        qDebug() << "video_index = " << video_index;
        qDebug() << "总帧数" << formatcontext->streams[video_index]->nb_frames;
    }

    //5.查找解码器
    AVCodecContext* codeccontext = formatcontext->streams[video_index]->codec;
    AVCodec* decoder = avcodec_find_decoder(codeccontext->codec_id);    //视频综合信息中的编码id
    //判断是否找到了
    if(decoder==nullptr)
    {
        qDebug() << "decoder no find";
    }
    else {
        qDebug() << "decoder success";
    }

    //6.打开解码器
    res = avcodec_open2(codeccontext, decoder, nullptr);
    //判断是否成功
    if(res!=0)
    {
        qDebug() << "decoder open fail";
    }
    else {
        qDebug() << "decorder open success";
    }

    //7.读一帧数据
    //*******AVPacket准备工作*****************/
    AVPacket* packet;
    packet = (AVPacket*)malloc(sizeof(AVPacket));
    int size = codeccontext->width*codeccontext->height;

    res = av_new_packet(packet,size);
    //判断是否成功
    if(res!=0)
    {
        qDebug() << "av_newpacket fail";
    }
    else {
        qDebug() << "av_newpacket success";
    }

    /********AVPacket准备工作...end*****************/

    /*******AVFrame RGB准备工作  为了在窗口中播放显示、截图*********************/

    AVFrame* pictureRGB;    //保存输出数据  解码出来的数据
    AVFrame* picture;       //保存，输入数据  视频数据
    picture = av_frame_alloc();
    pictureRGB = av_frame_alloc();
    pictureRGB->width = codeccontext->width;
    pictureRGB->height = codeccontext->height;
    pictureRGB->format = codeccontext->pix_fmt;

    //设置缓冲区
    int imgByteRGB = avpicture_get_size(AV_PIX_FMT_RGB32,codeccontext->width, codeccontext->height);
    uint8_t* bufferRGB = (uint8_t*) av_malloc(imgByteRGB* sizeof(uint8_t));
    //填充
    avpicture_fill((AVPicture*)pictureRGB, bufferRGB, AV_PIX_FMT_RGB32,
                   codeccontext->width, codeccontext->height);

    //设置一个图像规则，
    //前三个参数都是原视频中一帧数据的宽度 高度 以及格式
    //中间三个参数是解码以后的一阵画面 宽度 高度 格式
    //转换数据的算法SWS_BICUBIC  余下三个nullptr
    SwsContext* swscontextRGB = sws_getContext(codeccontext->width, codeccontext->height, codeccontext->pix_fmt,
                                               codeccontext->width, codeccontext->height,AV_PIX_FMT_RGB32,
                                               SWS_BICUBIC, nullptr, nullptr, nullptr);

    /*******AVFrame RGB准备工作...end*******************/

    /*******AVFrame YUV准备工作 为了后续的编码转码  YUV比RGB压缩率更高*************************/

    AVFrame* pictureYUV;
    pictureYUV = av_frame_alloc();
    pictureYUV->width = codeccontext->width;
    pictureYUV->height = codeccontext->height;
    pictureYUV->format = codeccontext->pix_fmt;

    //设置缓冲区
    int imgByteYUV = avpicture_get_size(AV_PIX_FMT_YUV420P, codeccontext->width, codeccontext->height);
    uint8_t* bufferYUV = (uint8_t*) av_malloc(imgByteYUV* sizeof(uint8_t));

    avpicture_fill((AVPicture*)pictureYUV, bufferYUV, AV_PIX_FMT_YUV420P,
            codeccontext->width, codeccontext->height);

    SwsContext* swscontextYUV = sws_getContext(codeccontext->width, codeccontext->height, codeccontext->pix_fmt,
                                               codeccontext->width, codeccontext->height,AV_PIX_FMT_YUV420P,
                                               SWS_BICUBIC, nullptr, nullptr, nullptr);



    /*******AVFrame YUV准备工作...end*******************/

    //视频是连续的读取，循环           ==0代表读到数据
    //读一帧，取packet包

//    while(this->isStop==false&&this->isRun==true)
//    {
//        qDebug() << this->isStop;
//        qDebug() << this->isRun;
//    }

//    while(this->isRun==true)


//    FILE* YUVfp
    int x= 0;
    while(this->isStop==false)
        if(this->isRun==true){
            if(av_read_frame(formatcontext,packet)==0)
            {
         //       if(this->isRun==true)

                if(packet->stream_index == video_index)
                {
                    //解码
                    int get_picture_ptr = -1;
                    //解码函数
                    avcodec_decode_video2(codeccontext, picture, &get_picture_ptr, packet);
                    if(get_picture_ptr!=0)
                    {
                        //---------------以下为了实现编码操作
                        //原视频avframe 转YUV数据格式的avframe
                        sws_scale(swscontextYUV, picture->data, picture->linesize, 0, picture->height,
                                pictureYUV->data, pictureYUV->linesize);        //数据格式转换


                        //------------------------以下操作为了在窗口UI中显示-------------------------------//
                        //原视频avframe 转RGB数据格式的avframe
                        sws_scale(swscontextRGB, picture->data, picture->linesize, 0, picture->height,
                                pictureRGB->data, pictureRGB->linesize);        //数据格式转换
                        img = QImage((uchar*)bufferRGB, codeccontext->width, codeccontext->height, QImage::Format_RGB32);
                        qDebug() << "x=" << x++;
                        //保存图片
                        //img.save(QString("../fileout/%1.jpg").arg(x));

                        //自定义信号发送图片给窗口
                        emit sendImg(img);

                        //毫秒为单位的延时 数值越大，播放速度越慢 播放倍速思维通过修改这个值来实现
                        msleep(this->speed);

                    }
                }

                //AVPacket包 清空
                av_packet_unref(packet);
            }
        }

    //解码器上下文关闭
    avcodec_close(codeccontext);
    //关闭文件
    avformat_close_input(&formatcontext);
}

int DecodeVideo::getSpeed() const
{
    return speed;
}

void DecodeVideo::setSpeed(int value)
{
    speed = value;
}

bool DecodeVideo::getIsRun() const
{
    return isRun;
}

void DecodeVideo::setIsRun(bool value)
{
    isRun = value;
}

bool DecodeVideo::getIsStop() const
{
    return isStop;
}

void DecodeVideo::setIsStop(bool value)
{
    isStop = value;
}

void DecodeVideo::run()
{
    this->openVideo();
}
